package com.base.invoke.okhttp.request;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.Map;

import com.base.invoke.okhttp.handle.RequestCallback;
import com.base.invoke.okhttp.request.PostReq.FileInfo;
import com.base.invoke.okhttp.callback.Callback;
import okhttp3.Headers;
import okhttp3.MediaType;
import okhttp3.MultipartBody;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.internal.Util;
import okio.BufferedSink;
import okio.Okio;
import okio.Source;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @desc OkHttp请求包装类，用来封装网络请求信息及请求体，比如请求方式（GET、POST、DELETE、PUT等），url，headers，请求参数等，
 * 服务器端最终接受并解析的请求消息，就是由该类提供。OkHttpClient获取Call对象时，需要传入Request作为参数；
 * @author coolpig
 * @date 2019-08-28
 */
public abstract class OkHttpReq {
	public static Logger logger = LoggerFactory.getLogger(OkHttpReq.class);
	protected int id;
	protected String url;
	protected Map<String, String> paramsMap;
	protected Map<String, String> encoParamsMap;
	protected Map<String, String> headersMap;
	protected String body;
	protected List<FileInfo> fileInfoList;
	protected MultipartBody multipartBody;
	protected Request.Builder builder = new Request.Builder();

	protected OkHttpReq(String url, Object tag, Map<String, String> paramsMap,
						Map<String, String> headersMap,
						List<FileInfo> fileInfoList,
						String body,
						MultipartBody multipartBody,
						int id) {
		this(url, tag, paramsMap, null, headersMap, fileInfoList, body, multipartBody, id);
	}
	protected OkHttpReq(String url, Object tag, Map<String, String> paramsMap,
						Map<String, String> encoParamsMap,
						Map<String, String> headersMap,
						List<FileInfo> fileInfoList,
						String body,
						MultipartBody multipartBody,
						int id) {
		this.url = url;
		this.paramsMap = paramsMap;
		this.encoParamsMap = encoParamsMap;
		this.headersMap = headersMap;
		this.fileInfoList = fileInfoList;
		this.body = body;
		this.multipartBody = multipartBody;
		this.id = id;
		if (url == null) throw new IllegalArgumentException("url must not null!");
		builder.url(url).tag(tag);
		appendHeaders();
	}

	protected abstract RequestBody buildRequestBody();
	
	protected abstract Request buildRequest(RequestBody requestBody);

	public RequestCallback build(OkHttpClient okHttpClient) {
		return new RequestCallback(this,okHttpClient);
	}

	public Request createRequest(Callback callback) {
		RequestBody requestBody=buildRequestBody();
		Request request = buildRequest(requestBody);
		return request;
	}

	protected void appendHeaders() {
		Headers.Builder headerBuilder = new Headers.Builder();
		if (headersMap == null || headersMap.isEmpty())
			return;
		for (String key : headersMap.keySet()) {
			headerBuilder.add(key, headersMap.get(key));
		}
		builder.headers(headerBuilder.build());
	}

	public int getId() {
		return id;
	}

	public static RequestBody setUpReqBodyInfo(final MediaType conType, final InputStream in) {

		if (null == in) throw new NullPointerException("InputStream == null");

		return new RequestBody() {
			@Override
			public MediaType contentType() {
				return conType;
			}

			@Override
			public long contentLength() {
				try {
					return in.available();
				} catch (IOException ex) {
					return 0;
				}finally {
					logger.info("get contentLength finished");
				}
			}

			@Override
			public void writeTo(BufferedSink bfSink) throws IOException {
				Source sc = null;
				try {
					sc = Okio.source(in);
					bfSink.writeAll(sc);
				} finally {
					Util.closeQuietly(sc);
				}
			}
		};
	}
}
